using BlockOS.ChunkStorage;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Pool;

namespace BlockOS.Client
{
    public class ClientWorld : MonoBehaviour
    {
        public Chunk chunkPrefab;
        public Entity entityPrefab;
        public Transform playerTransform;

        public Camera playerCamera;

        [SerializeField]
        private Transform mapRoot;
        [SerializeField]
        private Transform entityRoot;

        private AbstractChunkStorage storage;
        private IWorld logicalWorld;
        private ChunkManager chunkManager;
        private Dictionary<int, Entity> entities;

        public IWorld LogicalWorld => logicalWorld;
        public AbstractChunkStorage Storage => storage;

        private void Awake()
        {
            storage = null;
            chunkManager = new ChunkManager(this);
            entities = new Dictionary<int, Entity>();
        }

        private void OnDestroy()
        {
            playerTransform = null;
        }

        public void Bind(IWorld world)
        {
            logicalWorld = world;
            world.UploadPlayerTransform(playerTransform.position, playerTransform.eulerAngles);
        }

        public void Unbind()
        {
            logicalWorld = null;
            chunkManager.Clear();
        }

        public void UpdateEntity(int entityId, EntityData entityData)
        {
            if (entities.TryGetValue(entityId, out Entity entity))
            {
                entity.Refresh(entityData);
            }
            else
            {
                var e = Instantiate(entityPrefab, entityRoot);
                e.Refresh(entityData);
                entities.Add(entityId, e);
            }
        }

        public void LoadStorage(AbstractChunkStorage storage)
        {
            this.storage = storage;
            storage.onChunkDataLoad += chunkManager.AddChunk;
            chunkManager.Update(playerTransform.position);
            StartCoroutine(CoChunkUpdateService());
        }

        public void UnloadStorage()
        {
            storage.onChunkDataLoad -= chunkManager.AddChunk;
            storage = null;
            chunkManager.Clear();
        }

        private void Update()
        {
            storage?.Update();
        }

        private IEnumerator CoChunkUpdateService()
        {
            while (gameObject.activeSelf && storage != null)
            {
                chunkManager.Update(playerTransform.position);
                yield return new WaitForSeconds(0.75f);
            }
        }

        public Chunk CreateChunkObj()
        {
            return Instantiate(chunkPrefab, mapRoot);
        }
    }
}
